Skip to content

Follow-up: tackle 5 of 6 post-refactor TODOs (motor_poles, fold events, field_names, pub-cleanup, dead_code)#6

Merged
Iteratrix merged 3 commits into
mainfrom
followup/session-todos
May 5, 2026
Merged

Follow-up: tackle 5 of 6 post-refactor TODOs (motor_poles, fold events, field_names, pub-cleanup, dead_code)#6
Iteratrix merged 3 commits into
mainfrom
followup/session-todos

Conversation

@Iteratrix

Copy link
Copy Markdown
Owner

Summary

Five of the six in-code TODOs left over from the typed-Session refactor (PR #5). The sixth (typed PID-term traces in Session) is left for a focused follow-up since it's a Session schema change that only BF can populate.

Commits

What's externally visible

  • SessionMeta gains motor_poles: Option<u32> (BF populates it from headers; AP/PX4/MAVLink leave None).
  • FFT analysis uses session.meta.motor_poles.unwrap_or(14) instead of hard-coded 14.
  • FlightAnalysis.events now includes folded Session events (mode changes, armed/disarmed, firmware messages, failsafes) as FirmwareMessage variants. Frontend timeline sees state changes alongside behavior-detected events.
  • Session::field_by_name(&str) -> Vec<f64> — recommended public API for tools that take user-supplied field names.
  • Session::field(&SensorField) — now pub(crate). External callers migrate to field_by_name.
  • analysis::fft::compute_spectrogram takes &[(&str, &str)] (label, canonical name) instead of &[(&str, &SensorField)].
  • Session::field_names() is no longer a stub — it iterates all populated typed slots (gyro/accel/setpoint/attitude per axis, motors, eRPM per channel, RC sticks/throttle, vbat, current, rssi, all GPS columns, plus extras).
  • types::Unit deleted (was unused). types::SensorField, MotorIndex, RcChannel demoted to pub(crate).

Migrations carried out

  • propwash-cli: info command's hardcoded field() lookups replaced with typed checks; dump uses field_by_name.
  • propwash-web: get_dump, get_filter_config, get_spectrogram use field_by_name.
  • propwash-core/tests/perf.rs + examples/bench.rs: switched to field_by_name.

What's still TODO

  • TODO Review #5: migrate web frontend to TypeScript #4 (analyze_windup → return empty): typed PID-term traces (pid_p/pid_i/pid_d as TriaxialSeries) need to be added to Session, and BF parser needs to populate them. AP/PX4/MAVLink don't expose these. Worth its own PR with a Session schema discussion.

Test plan

  • cargo test --workspace — 150 lib + 21 integration + 20 CLI + 22 web bridge + 7 fft, all green.
  • cargo clippy --workspace --no-deps -- -D warnings — clean.
  • cargo fmt --check — clean.
  • CLI info against btfl_002.bbl shows 27 fields (was 14 stub-listed before).
  • Smoke check WASM frontend renders spectrogram via the new (&str, &str) interface.

🤖 Generated with Claude Code

Leah Wilson and others added 3 commits May 1, 2026 14:22
…ld_names, dead_code audit

#5 motor_poles: SessionMeta gets `motor_poles: Option<u32>`. BF build
populates it from the `motor_poles` header; AP/PX4/MAVLink leave None.
analysis::fft::analyze_vibration_unified reads
`session.meta.motor_poles.unwrap_or(14)` instead of hard-coding 14, so
real-world FFT eRPM→Hz conversion uses the right pole count for BF
logs (HD camera builds with 7-pole motors, 6-pole quads, etc.).

#3 fold session events: `analysis::analyze` now folds Session.events
(format-native: ModeChange, Armed/Disarmed, LogMessage, Failsafe,
GpsRescue, Crash, Custom) into FlightAnalysis.events as
FirmwareMessage variants with synthetic levels. Severities map
through cleanly; mode/armed/custom states get "info"; failsafe/crash
get "critical"; gps rescue gets "warning". Frontend timeline now
sees state changes alongside behavior-detected events without a
shape change. Added a fold regression test.

#1 field_names cleanup: was a stub listing only "time" + "gyro[*]" +
extras keys. Now iterates every populated typed slot — gyro/accel/
setpoint/attitude per-axis, motors[i] / erpm[i] per channel, rc
sticks + throttle, vbat / current / rssi, all GPS columns, plus
extras. CLI `info` against btfl_002.bbl now lists 27 fields (was
14). Used by `propwash dump` field name resolution and the WASM
raw-data tab.

#6 dead_code audit on analysis/util.rs: stripped the stale TODO
banner. Strategy enum and resample/resample_zoh shims kept as
public API with allow(dead_code) on the subset not currently
called by analysis (StepFill/Nearest variants, the TimeSeries-
taking shims) so the public surface stays available for future
callers without the lint flagging it. Documentation updated to
explain why each is kept.

Tests: 150 lib (+1 fold test) + 21 integration + 20 CLI + 22 web
+ 7 fft. All green; clippy clean; fmt clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rnal

Replaces the public stringly-typed Session::field(SensorField) bridge
with field_by_name(&str), the recommended entry point for tools that
take user-supplied field names at runtime (CLI dump, WASM raw-data
tab, WASM spectrogram). field() stays around as crate-internal for
the BF parser tables that key on SensorField, but is no longer part
of the public API.

Surface changes:

propwash-core public API:
- Session::field_by_name(&str) -> Vec<f64> (new) — recommended.
- Session::field(&SensorField) (now pub(crate)) — internal only.
- analysis::fft::compute_spectrogram now takes &[(&str, &str)]
  (axis label, canonical Session field name) instead of
  &[(&str, &SensorField)]. Routes through field_by_name internally.
- types::SensorField, MotorIndex, RcChannel demoted to pub(crate).
- types::Unit deleted (was unused — only referenced by the deleted
  SensorField::unit() method).
- types::RcChannel::index() deleted (unused).

Migrations:

propwash-cli/src/main.rs:
- info command: hardcoded ERpm/GyroUnfilt field() lookups replaced
  with typed checks (motors.esc.is_some() and an extras key).
- dump command: drops the SensorField::parse + field(field) two-step
  in favor of field_by_name(name) + filter empty results.

propwash-web/src/lib.rs:
- get_dump and get_filter_config: field_by_name.
- get_spectrogram: builds (label, canonical) string pairs for the
  new compute_spectrogram signature.

propwash-core/tests/perf.rs + examples/bench.rs: switch to
field_by_name with canonical field names ("gyro[roll]" etc.).

Tests: 150 lib + 21 integration + 20 CLI + 22 web + 7 fft. All green;
clippy clean; fmt clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SensorField, MotorIndex, RcChannel are now public (with FromStr,
Serialize, Deserialize, and feature-gated tsify-next derives).
Session::field(&SensorField) is the sole lookup-by-handle method;
field_by_name is gone.

WASM bridge takes a typed SensorFields newtype that crosses the
wasm-bindgen boundary as a TS discriminated union (SensorField[]),
generated automatically by tsify-next. JS callsites construct typed
field handles via a new parseSensorField helper that mirrors the Rust
parser.

CLI dump enumerates names via field_names(), prefix-filters, then
parses each survivor into SensorField (extras keys / attitude fall
back to Unknown, which yields an empty column). compute_spectrogram
takes typed (label, &[f64]) axes; perf + bench tests measure the
zero-cost cast_slice path with a 1ms ceiling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Iteratrix Iteratrix merged commit 750be48 into main May 5, 2026
11 checks passed
@Iteratrix Iteratrix deleted the followup/session-todos branch May 5, 2026 00:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant